import { 
  Column, 
  CellValue, 
  RenderContext,
  CellPosition,
  CellRange,
  ThemeOptions,
  SelectionMode
} from '../types'
import { DataManager } from '../data/DataManager'
import { VirtualScrollManager } from '../virtual-scroll/VirtualScrollManager'
import { defaultTheme, themeToTableOptions } from '../styles/theme'

// 添加脏区域类型
interface DirtyRegion {
  x: number
  y: number
  width: number
  height: number
}

// 文本测量缓存接口
interface TextMeasureCache {
  [key: string]: {
    width: number
    timestamp: number
  }
}

// LRU缓存类
class LRUCache<T> {
  private cache: Map<string, T> = new Map()
  private maxSize: number
  
  constructor(maxSize: number) {
    this.maxSize = maxSize
  }
  
  get(key: string): T | undefined {
    const value = this.cache.get(key)
    if (value !== undefined) {
      // 移到最后（最近使用）
      this.cache.delete(key)
      this.cache.set(key, value)
    }
    return value
  }
  
  set(key: string, value: T): void {
    // 如果已存在，先删除
    if (this.cache.has(key)) {
      this.cache.delete(key)
    } else if (this.cache.size >= this.maxSize) {
      // 删除最早的项（第一个）
      const firstKey = this.cache.keys().next().value
      if (firstKey !== undefined) {
        this.cache.delete(firstKey)
      }
    }
    this.cache.set(key, value)
  }
  
  clear(): void {
    this.cache.clear()
  }
  
  get size(): number {
    return this.cache.size
  }
}

// 默认主题
const DEFAULT_THEME: Required<ThemeOptions> = {
  ...themeToTableOptions(defaultTheme),
  primaryColor: defaultTheme.primary[500],
  headerBgColor: defaultTheme.neutral[50],
  headerTextColor: defaultTheme.neutral[900],
  cellBgColor: '#ffffff',
  cellTextColor: defaultTheme.neutral[900],
  selectedBgColor: defaultTheme.primary[100],
  selectedTextColor: defaultTheme.neutral[900],
  modifiedBgColor: defaultTheme.modified,
  borderColor: defaultTheme.border,
  fontFamily: defaultTheme.fontFamily,
  fontSize: defaultTheme.fontSize.sm
}

export class TableRenderer {
  private canvas: HTMLCanvasElement
  private ctx: CanvasRenderingContext2D
  private dataManager: DataManager
  private scrollManager: VirtualScrollManager
  private theme: Required<ThemeOptions>
  
  // 选择状态
  private selectedCells: Set<string> = new Set()
  private selectionRange: CellRange | null = null
  private currentCell: CellPosition | null = null
  private selectedRows: Set<number> = new Set()
  private selectedColumns: Set<number> = new Set()
  private selectionMode: SelectionMode = SelectionMode.Cell
  
  // 行号列宽度
  private rowNumberWidth: number = 50
  private showRowNumber: boolean = true
  private showGridLines: boolean = true
  
  // 编辑状态
  private editingCell: CellPosition | null = null
  
  // 悬停状态
  private hoveredCell: CellPosition | null = null
  private hoveredRow: number = -1
  private hoveredColumn: number = -1
  private isHoveringVerticalScrollbar: boolean = false
  private isHoveringHorizontalScrollbar: boolean = false

  // 调试日志
  private debugLogged: boolean = false
  private cellDebugLogged: boolean = false

  // 画布逻辑尺寸（不包含 DPR 缩放）
  private canvasLogicalWidth: number = 0
  private canvasLogicalHeight: number = 0
  
  // 分页信息
  private pageInfo: { currentPage: number; pageSize: number } = { currentPage: 1, pageSize: 0 }
  
  // 排序配置
  private sortConfig: { column: string | null; direction: 'asc' | 'desc' | null } = {
    column: null,
    direction: null
  }
  
  // 性能优化：脏区域管理
  private dirtyRegions: DirtyRegion[] = []
  private isFullRedrawNeeded: boolean = true
  
  // 性能优化：文本测量缓存
  private textMeasureCache: LRUCache<number> = new LRUCache<number>(5000)
  
  // 性能优化：离屏Canvas缓存
  private offscreenCanvas: HTMLCanvasElement | null = null
  private offscreenCtx: CanvasRenderingContext2D | null = null
  private needsOffscreenRedraw: boolean = true

  constructor(
    canvas: HTMLCanvasElement,
    dataManager: DataManager,
    scrollManager: VirtualScrollManager,
    options?: {
      theme?: ThemeOptions
      showRowNumber?: boolean
      showGridLines?: boolean
    }
  ) {
    this.canvas = canvas
    this.ctx = canvas.getContext('2d')!
    this.dataManager = dataManager
    this.scrollManager = scrollManager
    this.theme = { ...DEFAULT_THEME, ...options?.theme }
    this.showRowNumber = options?.showRowNumber ?? true
    this.showGridLines = options?.showGridLines ?? true
    
    // 获取画布的逻辑尺寸
    this.updateCanvasLogicalSize()
    
    // 设置默认字体
    this.ctx.font = `${this.theme.fontSize}px ${this.theme.fontFamily}`
    
    // 设置文本渲染质量
    this.ctx.textBaseline = 'middle'
    this.ctx.imageSmoothingEnabled = true
    this.ctx.imageSmoothingQuality = 'high'
    
    // 初始化离屏Canvas
    this.initOffscreenCanvas()
  }

  // 更新画布逻辑尺寸
  private updateCanvasLogicalSize(): void {
    const rect = this.canvas.getBoundingClientRect()
    this.canvasLogicalWidth = rect.width
    this.canvasLogicalHeight = rect.height
    
    // 同时更新离屏Canvas尺寸
    this.updateOffscreenCanvasSize()
  }

  // 渲染整个表格
  render(): void {
    // 更新画布逻辑尺寸
    this.updateCanvasLogicalSize()
    
    // 暂时总是使用全量渲染，避免脏区域计算的性能开销
    this.renderFull()
    this.resetDirtyRegions()
  }
  
  // 完整渲染
  private renderFull(): void {
    const startTime = performance.now()
    
    // 获取可视区域信息
    const viewport = this.scrollManager.getViewport()
    const containerSize = this.scrollManager.getContainerSize()
    
    // 清空画布
    this.ctx.clearRect(0, 0, this.canvasLogicalWidth, this.canvasLogicalHeight)
    
    // 绘制表头和固定的元素
    this.renderHeader(viewport)
    
    // 如果有数据，渲染内容
    const rowCount = this.dataManager.getRowCount()
    if (rowCount > 0) {
      // 绘制行号列（如果启用）
      if (this.showRowNumber) {
        this.renderRowNumbers(viewport)
      }
      
      // 使用离屏画布更新静态内容（如网格线）
      if (this.offscreenCanvas && this.needsOffscreenRedraw) {
        this.updateOffscreenCanvas(viewport)
        this.needsOffscreenRedraw = false
      }
      
      // 绘制离屏缓存的内容
      if (this.offscreenCanvas && this.offscreenCtx) {
        this.ctx.drawImage(
          this.offscreenCanvas, 
          0, 0, 
          this.offscreenCanvas.width, 
          this.offscreenCanvas.height,
          0, 0,
          this.canvasLogicalWidth,
          this.canvasLogicalHeight
        )
      } else {
        // 渲染网格线
        if (this.showGridLines) {
          this.renderGridLines(viewport)
        }
      }
      
      // 渲染动态内容（如单元格内容）
      this.renderDynamicContent(viewport)
    } else {
      // 即使没有数据，也绘制行号列背景
      if (this.showRowNumber) {
        const rowNumberBgColor = this.theme.headerBgColor || "#f3f4f6";
        this.ctx.fillStyle = rowNumberBgColor
        this.ctx.fillRect(0, this.scrollManager.getHeaderHeight(), this.rowNumberWidth, containerSize.height - this.scrollManager.getHeaderHeight())
      }
      
      // 绘制空表格信息
      this.renderEmptyTableMessage(containerSize)
      
      // 即使没有数据，也需要渲染以下元素：
      
      // 1. 渲染选择边框
      this.renderSelectionBorders(viewport)
      
      // 2. 渲染复制/剪切边框
      this.renderClipboardBorder(viewport)
      
      // 3. 渲染当前单元格边框
      if (this.currentCell) {
        this.renderCurrentCellBorder(this.currentCell)
      }
      
      // 4. 渲染编辑框边框
      if (this.editingCell) {
        this.renderEditingBorder(this.editingCell)
      }
      
      // 5. 渲染填充柄
      this.renderFillHandle()
    }
    
    // 总是绘制滚动条
    this.renderScrollbars()
    
    const endTime = performance.now()
    if (!this.debugLogged) {
      this.debugLogged = true
    }
  }
  
  // 新增：渲染空表格消息
  private renderEmptyTableMessage(containerSize: { width: number; height: number }): void {
    const message = "无数据"
    this.ctx.save()
    
    // 设置字体和样式
    this.ctx.font = `${this.theme.fontSize || 13}px ${this.theme.fontFamily}`
    this.ctx.textAlign = 'center'
    this.ctx.textBaseline = 'middle'
    this.ctx.fillStyle = this.theme.cellTextColor || "#6b7280"
    
    // 计算位置 - 在表格中心
    const x = this.showRowNumber ? 
      (this.rowNumberWidth + containerSize.width) / 2 : 
      containerSize.width / 2
    const y = (containerSize.height + this.scrollManager.getHeaderHeight()) / 2
    
    // 绘制文本
    this.ctx.fillText(message, x, y)
    this.ctx.restore()
  }
  
  // 更新离屏Canvas（静态内容）
  private updateOffscreenCanvas(viewport: any): void {
    if (!this.offscreenCanvas || !this.offscreenCtx) return
    
    const { width, height } = this.offscreenCanvas
    this.offscreenCtx.clearRect(0, 0, width, height)
    
    // 设置样式
    this.offscreenCtx.font = `${this.theme.fontSize}px ${this.theme.fontFamily}`
    
    // 渲染表格背景
    this.offscreenCtx.fillStyle = this.theme.cellBgColor
    this.offscreenCtx.fillRect(0, 0, width, height)
    
    // 渲染表头背景
    const headerHeight = this.scrollManager.getHeaderHeight()
    this.offscreenCtx.fillStyle = this.theme.headerBgColor
    this.offscreenCtx.fillRect(0, 0, width, headerHeight)
    
    // 渲染行号列背景
    if (this.showRowNumber) {
      this.offscreenCtx.fillStyle = this.theme.headerBgColor
      this.offscreenCtx.fillRect(0, headerHeight, this.rowNumberWidth, height - headerHeight)
    }
    
    // 渲染网格线（静态部分）
    if (this.showGridLines) {
      this.renderStaticGridLines(this.offscreenCtx, viewport)
    }
    
    this.needsOffscreenRedraw = false
  }
  
  // 渲染静态网格线到指定上下文
  private renderStaticGridLines(ctx: CanvasRenderingContext2D, viewport: any): void {
    ctx.strokeStyle = this.theme.borderColor
    ctx.lineWidth = 1
    
    const headerHeight = this.scrollManager.getHeaderHeight()
    
    // 绘制水平线（表头下方）
    ctx.beginPath()
    ctx.moveTo(0, headerHeight)
    ctx.lineTo(this.canvasLogicalWidth, headerHeight)
    ctx.stroke()
    
    // 绘制垂直线（行号列右侧）
    if (this.showRowNumber) {
      ctx.beginPath()
      ctx.moveTo(this.rowNumberWidth, 0)
      ctx.lineTo(this.rowNumberWidth, this.canvasLogicalHeight)
      ctx.stroke()
    }
  }
  
  // 渲染动态内容
  private renderDynamicContent(viewport: any): void {
    // 1. 渲染主体单元格
    this.renderCells(viewport)
    
    // 2. 渲染表头
    this.renderHeader(viewport)
    
    // 3. 渲染行号列
    if (this.showRowNumber) {
      this.renderRowNumbers(viewport)
    }
    
    // 4. 渲染动态网格线
    if (this.showGridLines) {
      this.renderGridLines(viewport)
    }
    
    // 5. 渲染选择边框
    this.renderSelectionBorders(viewport)
    
    // 6. 渲染复制/剪切边框
    this.renderClipboardBorder(viewport)
    
    // 7. 渲染当前单元格边框
    if (this.currentCell) {
      this.renderCurrentCellBorder(this.currentCell)
    }
    
    // 8. 渲染滚动条
    this.renderScrollbars()
    
    // 9. 渲染编辑框边框
    if (this.editingCell) {
      this.renderEditingBorder(this.editingCell)
    }
    
    // 10. 渲染填充柄
    this.renderFillHandle()
  }

  // 渲染单元格
  private renderCells(viewport: any): void {
    const columns = this.dataManager['columns']
    const headerHeight = ('getHeaderHeight' in this.scrollManager) 
      ? (this.scrollManager as any).getHeaderHeight() 
      : (this.scrollManager as any).headerHeight || 35
    
    // 保存当前状态
    this.ctx.save()
    
    // 设置通用样式
    this.ctx.textAlign = 'left'
    this.ctx.textBaseline = 'middle'
    this.ctx.font = `${this.theme.fontSize}px ${this.theme.fontFamily}`
    
    // 渲染数据单元格
    const totalRows = this.dataManager.getRowCount()
    for (let row = viewport.startRow; row <= viewport.endRow && row < totalRows; row++) {
      const y = this.scrollManager.getRowY(row)
      const rowHeight = this.scrollManager.getRowHeight(row)
      
      // 跳过不可见的行
      if (y + rowHeight < headerHeight || y > this.canvasLogicalHeight) {
        continue
      }
      
      // 预计算行状态
      const isRowSelected = this.selectedRows.has(row)
      const isRowHovered = this.hoveredRow === row
      const isInsertedRow = this.dataManager.getInsertedRows().has(row)
      
      for (let col = viewport.startCol; col <= viewport.endCol; col++) {
        const column = columns[col]
        const x = this.scrollManager.getColumnX(col) + this.rowNumberWidth  // 始终加上行号列宽度
        const width = column.width || 100
        
        // 跳过不可见的列
        if (x + width < 0 || x > this.canvasLogicalWidth) {
          continue
        }
        
        // 获取单元格值
        const value = this.dataManager.getCellValue(row, column.field)
        
        const isSelected = this.isCellSelected(row, col) || isRowSelected || this.selectedColumns.has(col)
        const isModified = this.dataManager.getModifiedCells().has(`${row}:${column.field}`)
        const isHovered = (this.hoveredCell?.row === row && this.hoveredCell?.col === col) ||
                         isRowHovered || (this.hoveredColumn === col)
        
        // 渲染单元格背景
        this.renderCellBackground(x, y, width, rowHeight, {
          isSelected,
          isModified,
          isInserted: isInsertedRow,
          isHovered
        })
        
        // 渲染单元格内容
        this.renderCellContent(x, y, width, rowHeight, value, column)
      }
    }
    
    // 恢复状态
    this.ctx.restore()
  }

  // 渲染单元格背景
  private renderCellBackground(
    x: number, 
    y: number, 
    width: number, 
    height: number,
    state: {
      isSelected: boolean
      isModified: boolean
      isInserted: boolean
      isHovered: boolean
    }
  ): void {
    if (state.isSelected) {
      this.ctx.fillStyle = this.theme.selectedBgColor
    } else if (state.isInserted) {
      this.ctx.fillStyle = defaultTheme.inserted // 使用主题中的插入行颜色
    } else if (state.isModified) {
      this.ctx.fillStyle = this.theme.modifiedBgColor
    } else if (state.isHovered) {
      this.ctx.fillStyle = defaultTheme.hover // 使用主题中的悬停颜色
    } else {
      this.ctx.fillStyle = this.theme.cellBgColor
    }
    
    this.ctx.fillRect(x, y, width, height)
  }

  // 渲染单元格内容
  private renderCellContent(
    x: number,
    y: number,
    width: number,
    height: number,
    value: CellValue,
    column: Column
  ): void {
    const padding = 8
    const textY = y + height / 2
    
    // 设置文本样式
    this.ctx.fillStyle = this.theme.cellTextColor
    this.ctx.textAlign = 'left'
    this.ctx.textBaseline = 'middle'
    
    // 格式化值
    let displayValue = ''
    if (value === null || value === undefined) {
      displayValue = 'NULL'
      this.ctx.fillStyle = defaultTheme.neutral[400] // 使用主题的中性色
      this.ctx.font = `italic ${this.theme.fontSize}px ${this.theme.fontFamily}`
    } else if (column.formatter) {
      displayValue = column.formatter(value)
    } else {
      displayValue = String(value)
    }
    
    // 检查是否需要显示排序指示器
    const isSorted = this.sortConfig.column === column.field
    const sortIndicatorWidth = isSorted ? 15 : 0  // 只在已排序时预留空间给箭头
    
    // 计算可用宽度（减去两边的padding和排序指示器）
    const availableWidth = width - padding * 2 - sortIndicatorWidth
    
    // 测量文本宽度（使用缓存）
    const textWidth = this.measureTextCached(displayValue)
    
    // 保存当前状态
    this.ctx.save()
    
    // 设置裁剪区域
    this.ctx.beginPath()
    this.ctx.rect(x, y, width, height)
    this.ctx.clip()
    
    // 如果文本宽度超过可用宽度，显示省略号
    if (textWidth > availableWidth) {
      // 计算能显示的文本长度
      const ellipsis = '...'
      const ellipsisWidth = this.measureTextCached(ellipsis)
      const maxTextWidth = availableWidth - ellipsisWidth
      
      // 二分查找合适的文本长度
      let text = displayValue
      let low = 0
      let high = text.length
      let bestFit = ''
      
      while (low <= high) {
        const mid = Math.floor((low + high) / 2)
        const testText = text.substring(0, mid)
        const testWidth = this.measureTextCached(testText)
        
        if (testWidth <= maxTextWidth) {
          bestFit = testText
          low = mid + 1
        } else {
          high = mid - 1
        }
      }
      
      // 绘制截断的文本和省略号
      if (column.align === 'center') {
        this.ctx.textAlign = 'left'
        const totalWidth = this.measureTextCached(bestFit + ellipsis)
        const textX = x + (width - totalWidth) / 2
        this.ctx.fillText(bestFit + ellipsis, textX, textY)
      } else if (column.align === 'right') {
        this.ctx.fillText(bestFit + ellipsis, x + width - padding, textY)
      } else {
        this.ctx.fillText(bestFit + ellipsis, x + padding, textY)
      }
    } else {
      // 文本不超过宽度，正常显示
    if (column.align === 'center') {
      this.ctx.textAlign = 'center'
      this.ctx.fillText(displayValue, x + width / 2, textY)
    } else if (column.align === 'right') {
      this.ctx.textAlign = 'right'
      this.ctx.fillText(displayValue, x + width - padding, textY)
    } else {
        this.ctx.fillText(displayValue, x + padding, textY)
      }
    }
    
    this.ctx.restore()
    
    // 恢复默认字体
    if (value === null || value === undefined) {
      this.ctx.font = `${this.theme.fontSize}px ${this.theme.fontFamily}`
    }
  }

  // 渲染表头
  private renderHeader(viewport: any): void {
    const columns = this.dataManager['columns']
    const headerHeight = ('getHeaderHeight' in this.scrollManager) 
      ? (this.scrollManager as any).getHeaderHeight() 
      : (this.scrollManager as any).headerHeight || 35
    
    // 表头背景
    this.ctx.fillStyle = this.theme.headerBgColor
    this.ctx.fillRect(0, 0, this.canvasLogicalWidth, headerHeight)
    
    // 渲染列标题
    for (let col = viewport.startCol; col <= viewport.endCol; col++) {
      const column = columns[col]
      const x = this.scrollManager.getColumnX(col) + this.rowNumberWidth
      const width = column.width || 100
      
      // 跳过不可见的列
      if (x + width < 0 || x > this.canvasLogicalWidth) {
        continue
      }
      
      // 渲染列标题文本
      this.ctx.fillStyle = this.theme.headerTextColor
      this.ctx.font = `bold ${this.theme.fontSize}px ${this.theme.fontFamily}`
      this.ctx.textAlign = column.headerAlign || 'left'
      this.ctx.textBaseline = 'middle'
      
      const padding = 8
      const textY = headerHeight / 2
      
      // 检查是否需要显示排序指示器
      const isSorted = this.sortConfig.column === column.field
      
      // 计算可用宽度（减去两边的padding和排序指示器）
      const availableWidth = width - padding * 2
      
      // 测量文本宽度（使用缓存）
      const boldFont = `bold ${this.theme.fontSize}px ${this.theme.fontFamily}`
      const textWidth = this.measureTextCached(column.title, boldFont)
      
      // 保存当前状态
      this.ctx.save()
      
      // 设置裁剪区域
      this.ctx.beginPath()
      this.ctx.rect(x, 0, width, headerHeight)
      this.ctx.clip()
      
      // 如果文本宽度超过可用宽度，显示省略号
      if (textWidth > availableWidth) {
        // 计算能显示的文本长度
        const ellipsis = '...'
        const ellipsisWidth = this.measureTextCached(ellipsis, boldFont)
        const maxTextWidth = availableWidth - ellipsisWidth
        
        // 二分查找合适的文本长度
        let text = column.title
        let low = 0
        let high = text.length
        let bestFit = ''
        
        while (low <= high) {
          const mid = Math.floor((low + high) / 2)
          const testText = text.substring(0, mid)
          const testWidth = this.measureTextCached(testText, boldFont)
          
          if (testWidth <= maxTextWidth) {
            bestFit = testText
            low = mid + 1
          } else {
            high = mid - 1
          }
        }
        
        // 绘制截断的文本和省略号
        if (column.headerAlign === 'center' || column.align === 'center') {
          this.ctx.textAlign = 'left'
          const totalWidth = this.measureTextCached(bestFit + ellipsis, boldFont)
          const textX = x + (width - totalWidth) / 2
          this.ctx.fillText(bestFit + ellipsis, textX, textY)
        } else if (column.headerAlign === 'right' || column.align === 'right') {
          this.ctx.fillText(bestFit + ellipsis, x + width - padding, textY)
        } else {
          this.ctx.fillText(bestFit + ellipsis, x + padding, textY)
        }
      } else {
        // 文本不超过宽度，正常显示
      if (column.headerAlign === 'center' || column.align === 'center') {
        this.ctx.fillText(column.title, x + width / 2, textY)
      } else if (column.headerAlign === 'right' || column.align === 'right') {
        this.ctx.fillText(column.title, x + width - padding, textY)
      } else {
        this.ctx.fillText(column.title, x + padding, textY)
        }
      }
      
      // 绘制排序指示器
      if (isSorted && column.sortable !== false) {
        const indicatorText = this.sortConfig.direction === 'asc' ? ' ↑' : ' ↓'
        
        // 测量标题文字的宽度
        const titleWidth = this.measureTextCached(column.title, boldFont)
        
        // 根据对齐方式确定指示器的位置
        let indicatorX = x + padding + titleWidth + 2 // 默认左对齐
        
        if (column.headerAlign === 'center' || column.align === 'center') {
          indicatorX = x + width / 2 + titleWidth / 2 + 2
        } else if (column.headerAlign === 'right' || column.align === 'right') {
          // 右对齐时，指示器在文字前面
          indicatorX = x + width - padding - titleWidth - 15
        }
        
        const indicatorY = headerHeight / 2
        
        // 使用与标题相同的字体和颜色
        this.ctx.save()
        this.ctx.font = boldFont
        this.ctx.fillStyle = this.theme.headerTextColor
        this.ctx.textAlign = 'left'
        this.ctx.textBaseline = 'middle'
        this.ctx.fillText(indicatorText, indicatorX, indicatorY)
        this.ctx.restore()
      }
      
      this.ctx.restore()
    }
    
    // 恢复默认字体
    this.ctx.font = `${this.theme.fontSize}px ${this.theme.fontFamily}`
    
    // 渲染行号列的表头（始终显示）
    this.ctx.fillStyle = this.theme.headerBgColor
    this.ctx.fillRect(0, 0, this.rowNumberWidth, headerHeight)
    
    // 如果显示行号，在左上角绘制全选图标或文字
    if (this.showRowNumber) {
      // 检查是否全选状态（所有单元格都被选中）
      const isAllSelected = this.selectionRange && 
        this.selectionRange.start.row === 0 && 
        this.selectionRange.start.col === 0 &&
        this.selectionRange.end.row === this.dataManager.getRowCount() - 1 &&
        this.selectionRange.end.col === columns.length - 1
      
      // 绘制全选按钮区域
      if (isAllSelected) {
        // 如果已全选，绘制高亮背景
        this.ctx.fillStyle = defaultTheme.primary[200]
        this.ctx.fillRect(0, 0, this.rowNumberWidth, headerHeight)
      }
      
      // 绘制全选图标（一个小方块带对勾或斜线）
      const iconSize = 12
      const iconX = (this.rowNumberWidth - iconSize) / 2
      const iconY = (headerHeight - iconSize) / 2
      
      // 绘制边框
      this.ctx.strokeStyle = this.theme.headerTextColor
      this.ctx.lineWidth = 1
      this.ctx.strokeRect(iconX, iconY, iconSize, iconSize)
      
      if (isAllSelected) {
        // 绘制对勾
        this.ctx.beginPath()
        this.ctx.moveTo(iconX + 2, iconY + iconSize / 2)
        this.ctx.lineTo(iconX + iconSize / 2 - 1, iconY + iconSize - 3)
        this.ctx.lineTo(iconX + iconSize - 2, iconY + 3)
        this.ctx.stroke()
      } else {
        // 绘制一个小点或斜线表示可以点击全选
        this.ctx.fillStyle = this.theme.headerTextColor
        this.ctx.fillRect(iconX + 4, iconY + 4, 4, 4)
      }
    }
    
    // 绘制行号列表头的分隔线
    this.ctx.strokeStyle = this.theme.borderColor
    this.ctx.beginPath()
    this.ctx.moveTo(this.rowNumberWidth, 0)
    this.ctx.lineTo(this.rowNumberWidth, headerHeight)
    this.ctx.stroke()
  }

  // 渲染行号
  private renderRowNumbers(viewport: any): void {
    const headerHeight = ('getHeaderHeight' in this.scrollManager) 
      ? (this.scrollManager as any).getHeaderHeight() 
      : (this.scrollManager as any).headerHeight || 35
    
    // 行号列背景 - 始终渲染
    this.ctx.fillStyle = this.theme.headerBgColor
    this.ctx.fillRect(0, headerHeight, this.rowNumberWidth, this.canvasLogicalHeight - headerHeight)
    
    // 只有在showRowNumber为true时才渲染行号文本
    if (this.showRowNumber) {
      // 获取分页信息
      const rowOffset = this.pageInfo.pageSize > 0 ? (this.pageInfo.currentPage - 1) * this.pageInfo.pageSize : 0
    
      // 渲染行号
      for (let row = viewport.startRow; row <= viewport.endRow; row++) {
        const y = this.scrollManager.getRowY(row)
        const rowHeight = this.scrollManager.getRowHeight(row)
        
        // 跳过不可见的行
        if (y + rowHeight < headerHeight || y > this.canvasLogicalHeight) {
          continue
        }
        
        // 行号文本 - 根据分页计算实际行号
        const displayRowNumber = row + 1 + rowOffset
        this.ctx.fillStyle = this.theme.headerTextColor
        this.ctx.textAlign = 'center'
        this.ctx.textBaseline = 'middle'
        this.ctx.fillText(String(displayRowNumber), this.rowNumberWidth / 2, y + rowHeight / 2)
      }
    }
  }

  // 渲染网格线
  private renderGridLines(viewport: any): void {
    const columns = this.dataManager['columns']
    const headerHeight = ('getHeaderHeight' in this.scrollManager) 
      ? (this.scrollManager as any).getHeaderHeight() 
      : (this.scrollManager as any).headerHeight || 35
    
    this.ctx.strokeStyle = this.theme.borderColor
    this.ctx.lineWidth = 1
    
    // 垂直线
    let x = this.rowNumberWidth  // 始终从行号列宽度开始
    for (let col = viewport.startCol; col <= viewport.endCol + 1; col++) {
      if (col < columns.length) {
        x = this.scrollManager.getColumnX(col) + this.rowNumberWidth  // 始终加上行号列宽度
      } else {
        x += columns[columns.length - 1].width || 100
      }
      
      if (x >= 0 && x <= this.canvasLogicalWidth) {
        this.ctx.beginPath()
        this.ctx.moveTo(x, 0)
        this.ctx.lineTo(x, this.canvasLogicalHeight)
        this.ctx.stroke()
      }
    }
    
    // 水平线
    // 表头分隔线
    this.ctx.beginPath()
    this.ctx.moveTo(0, headerHeight)
    this.ctx.lineTo(this.canvasLogicalWidth, headerHeight)
    this.ctx.stroke()
    
    // 数据行分隔线（考虑动态行高）
    for (let row = viewport.startRow; row <= viewport.endRow + 1; row++) {
      const y = this.scrollManager.getRowY(row)
      
      if (y >= headerHeight && y <= this.canvasLogicalHeight) {
        this.ctx.beginPath()
        this.ctx.moveTo(0, y)
        this.ctx.lineTo(this.canvasLogicalWidth, y)
        this.ctx.stroke()
      }
    }
  }

  // 渲染滚动条
  private renderScrollbars(): void {
    const scrollbarInfo = this.scrollManager.getScrollbarInfo()
    const scrollbarWidth = ('getScrollbarWidth' in this.scrollManager) 
      ? (this.scrollManager as any).getScrollbarWidth() 
      : (this.scrollManager as any).scrollbarWidth || 10
    
    // 滚动条内边距
    const padding = 2
    const trackWidth = scrollbarWidth - padding * 2
    
    // 垂直滚动条
    if (scrollbarInfo.vertical.visible) {
      // 滚动条轨道（不透明背景）
      this.ctx.fillStyle = '#f3f4f6'  // 浅灰色背景
      this.ctx.fillRect(
        this.canvasLogicalWidth - scrollbarWidth,
        0,
        scrollbarWidth,
        this.canvasLogicalHeight - (scrollbarInfo.horizontal.visible ? scrollbarWidth : 0)
      )
      
      // 滚动条滑块
      const thumbY = scrollbarInfo.vertical.position + padding
      const thumbHeight = Math.max(scrollbarInfo.vertical.thumbSize - padding * 2, 10)
      
      // 绘制圆角滑块
      this.drawRoundedRect(
        this.canvasLogicalWidth - scrollbarWidth + padding,
        thumbY,
        trackWidth,
        thumbHeight,
        trackWidth / 2,  // 圆角半径为宽度的一半，形成圆形端部
        this.isHoveringVerticalScrollbar ? '#6b7280' : '#9ca3af'  // 悬停时深灰色，默认中灰色
      )
    }
    
    // 水平滚动条
    if (scrollbarInfo.horizontal.visible) {
      // 滚动条轨道（不透明背景）
      this.ctx.fillStyle = '#f3f4f6'  // 浅灰色背景
      this.ctx.fillRect(
        0,
        this.canvasLogicalHeight - scrollbarWidth,
        this.canvasLogicalWidth - (scrollbarInfo.vertical.visible ? scrollbarWidth : 0),
        scrollbarWidth
      )
      
      // 滚动条滑块
      const thumbX = scrollbarInfo.horizontal.position + padding
      const thumbWidth = Math.max(scrollbarInfo.horizontal.thumbSize - padding * 2, 10)
      
      // 绘制圆角滑块
      this.drawRoundedRect(
        thumbX,
        this.canvasLogicalHeight - scrollbarWidth + padding,
        thumbWidth,
        trackWidth,
        trackWidth / 2,  // 圆角半径为高度的一半，形成圆形端部
        this.isHoveringHorizontalScrollbar ? '#6b7280' : '#9ca3af'  // 悬停时深灰色，默认中灰色
      )
    }
    
    // 右下角交叉区域
    if (scrollbarInfo.vertical.visible && scrollbarInfo.horizontal.visible) {
      this.ctx.fillStyle = '#f3f4f6'  // 浅灰色背景
      this.ctx.fillRect(
        this.canvasLogicalWidth - scrollbarWidth,
        this.canvasLogicalHeight - scrollbarWidth,
        scrollbarWidth,
        scrollbarWidth
      )
    }
  }
  
  // 绘制圆角矩形辅助方法
  private drawRoundedRect(
    x: number,
    y: number,
    width: number,
    height: number,
    radius: number,
    fillColor: string
  ): void {
    // 限制圆角半径不超过矩形尺寸的一半
    radius = Math.min(radius, width / 2, height / 2)
    
    this.ctx.fillStyle = fillColor
    this.ctx.beginPath()
    
    // 从左上角开始
    this.ctx.moveTo(x + radius, y)
    
    // 顶边
    this.ctx.lineTo(x + width - radius, y)
    
    // 右上角
    this.ctx.arcTo(x + width, y, x + width, y + radius, radius)
    
    // 右边
    this.ctx.lineTo(x + width, y + height - radius)
    
    // 右下角
    this.ctx.arcTo(x + width, y + height, x + width - radius, y + height, radius)
    
    // 底边
    this.ctx.lineTo(x + radius, y + height)
    
    // 左下角
    this.ctx.arcTo(x, y + height, x, y + height - radius, radius)
    
    // 左边
    this.ctx.lineTo(x, y + radius)
    
    // 左上角
    this.ctx.arcTo(x, y, x + radius, y, radius)
    
    this.ctx.closePath()
    this.ctx.fill()
  }

  // 渲染编辑框边框
  private renderEditingBorder(cell: CellPosition): void {
    const columns = this.dataManager['columns']
    
    // 检查列索引是否有效
    if (cell.col < 0 || cell.col >= columns.length) return
    
    const column = columns[cell.col]
    if (!column) return
    
    const x = this.scrollManager.getColumnX(cell.col) + this.rowNumberWidth  // 始终加上行号列宽度
    const y = this.scrollManager.getRowY(cell.row)
    const width = column.width || 100
    const height = this.scrollManager.getRowHeight(cell.row)
    
    // 设置剪切区域
    this.ctx.save()
    const headerHeight = ('getHeaderHeight' in this.scrollManager) 
      ? (this.scrollManager as any).getHeaderHeight() 
      : (this.scrollManager as any).headerHeight || 35
    
    const scrollbarWidth = ('getScrollbarWidth' in this.scrollManager) 
      ? (this.scrollManager as any).getScrollbarWidth() 
      : (this.scrollManager as any).scrollbarWidth || 10
    const scrollbarInfo = this.scrollManager.getScrollbarInfo()
    const clipWidth = this.canvasLogicalWidth - (scrollbarInfo.vertical.visible ? scrollbarWidth : 0)
    const clipHeight = this.canvasLogicalHeight - headerHeight - (scrollbarInfo.horizontal.visible ? scrollbarWidth : 0)
    
    this.ctx.beginPath()
    this.ctx.rect(0, headerHeight, clipWidth, clipHeight)
    this.ctx.clip()
    
    this.ctx.strokeStyle = this.theme.primaryColor
    this.ctx.lineWidth = 2
    this.ctx.strokeRect(x, y, width, height)
    
    this.ctx.restore()
  }

  // 渲染选择边框
  private renderSelectionBorders(viewport: any): void {
    // 设置剪切区域
    this.ctx.save()
    const headerHeight = ('getHeaderHeight' in this.scrollManager) 
      ? (this.scrollManager as any).getHeaderHeight() 
      : (this.scrollManager as any).headerHeight || 35
    
    const scrollbarWidth = ('getScrollbarWidth' in this.scrollManager) 
      ? (this.scrollManager as any).getScrollbarWidth() 
      : (this.scrollManager as any).scrollbarWidth || 10
    const scrollbarInfo = this.scrollManager.getScrollbarInfo()
    const clipWidth = this.canvasLogicalWidth - (scrollbarInfo.vertical.visible ? scrollbarWidth : 0)
    const clipHeight = this.canvasLogicalHeight - headerHeight - (scrollbarInfo.horizontal.visible ? scrollbarWidth : 0)
    
    this.ctx.beginPath()
    this.ctx.rect(0, headerHeight, clipWidth, clipHeight)
    this.ctx.clip()
    
    if (this.selectionRange) {
      // 渲染范围选择边框
      const minRow = Math.min(this.selectionRange.start.row, this.selectionRange.end.row)
      const maxRow = Math.max(this.selectionRange.start.row, this.selectionRange.end.row)
      const minCol = Math.min(this.selectionRange.start.col, this.selectionRange.end.col)
      const maxCol = Math.max(this.selectionRange.start.col, this.selectionRange.end.col)
      
      // 计算边框位置
      const columns = this.dataManager['columns']
      
      // 使用 scrollManager 的方法来获取考虑了滚动偏移的坐标
      const x1 = this.scrollManager.getColumnX(minCol) + this.rowNumberWidth
      const x2 = this.scrollManager.getColumnX(maxCol) + (columns[maxCol]?.width || 100) + this.rowNumberWidth
      
      const y1 = this.scrollManager.getRowY(minRow)
      const y2 = this.scrollManager.getRowY(maxRow + 1)
      
      // 绘制选择边框
      this.ctx.strokeStyle = this.theme.primaryColor
      this.ctx.lineWidth = 2
      this.ctx.setLineDash([])
      
      this.ctx.strokeRect(x1, y1, x2 - x1, y2 - y1)
    } else if (this.selectedCells.size > 0) {
      // 渲染多选单元格边框
      this.ctx.strokeStyle = this.theme.primaryColor
      this.ctx.lineWidth = 1
      this.ctx.setLineDash([3, 3])
      
      this.selectedCells.forEach(key => {
        const [row, col] = key.split(':').map(Number)
        if (row >= viewport.startRow && row <= viewport.endRow && col >= viewport.startCol && col <= viewport.endCol) {
          const columns = this.dataManager['columns']
          const column = columns[col]
          const x = this.scrollManager.getColumnX(col) + this.rowNumberWidth  // 始终加上行号列宽度
          const y = this.scrollManager.getRowY(row)
          const width = column.width || 100
          const height = this.scrollManager.getRowHeight(row)
          
          this.ctx.strokeRect(x + 0.5, y + 0.5, width - 1, height - 1)
        }
      })
      
      this.ctx.setLineDash([])
    }
    
    this.ctx.restore()
  }
  
  // 渲染当前单元格边框
  private renderCurrentCellBorder(cell: CellPosition): void {
    const columns = this.dataManager['columns']
    
    // 检查列索引是否有效
    if (cell.col < 0 || cell.col >= columns.length) return
    
    const column = columns[cell.col]
    if (!column) return
    
    const x = this.scrollManager.getColumnX(cell.col) + this.rowNumberWidth  // 始终加上行号列宽度
    const y = this.scrollManager.getRowY(cell.row)
    const width = column.width || 100
    const height = this.scrollManager.getRowHeight(cell.row)
    
    // 设置剪切区域，确保边框不会显示在表格外面
    this.ctx.save()
    const headerHeight = ('getHeaderHeight' in this.scrollManager) 
      ? (this.scrollManager as any).getHeaderHeight() 
      : (this.scrollManager as any).headerHeight || 35
    
    // 剪切区域应该是整个表格内容区域（不包括滚动条）
    const scrollbarWidth = ('getScrollbarWidth' in this.scrollManager) 
      ? (this.scrollManager as any).getScrollbarWidth() 
      : (this.scrollManager as any).scrollbarWidth || 10
    const scrollbarInfo = this.scrollManager.getScrollbarInfo()
    const clipWidth = this.canvasLogicalWidth - (scrollbarInfo.vertical.visible ? scrollbarWidth : 0)
    const clipHeight = this.canvasLogicalHeight - headerHeight - (scrollbarInfo.horizontal.visible ? scrollbarWidth : 0)
    
    this.ctx.beginPath()
    this.ctx.rect(0, headerHeight, clipWidth, clipHeight)
    this.ctx.clip()
    
    // 绘制当前单元格边框（比选择边框稍细）
    this.ctx.strokeStyle = this.theme.primaryColor // 使用主题色而不是深色
    this.ctx.lineWidth = 1.5
    this.ctx.setLineDash([])
    this.ctx.strokeRect(x, y, width, height)
    
    this.ctx.restore()
  }

  // 设置选中的单元格
  setSelectedCells(cells: CellPosition[]): void {
    // 标记旧的选中单元格为脏区域
    this.selectedCells.forEach(key => {
      const [row, col] = key.split(':').map(Number)
      this.markCellDirty(row, col)
    })
    
    this.selectedCells.clear()
    cells.forEach(cell => {
      this.selectedCells.add(`${cell.row}:${cell.col}`)
      // 标记新的选中单元格为脏区域
      this.markCellDirty(cell.row, cell.col)
    })
  }

  // 设置选择范围
  setSelectionRange(range: CellRange | null): void {
    // 标记旧的选择范围为脏区域
    if (this.selectionRange) {
      const minRow = Math.min(this.selectionRange.start.row, this.selectionRange.end.row)
      const maxRow = Math.max(this.selectionRange.start.row, this.selectionRange.end.row)
      const minCol = Math.min(this.selectionRange.start.col, this.selectionRange.end.col)
      const maxCol = Math.max(this.selectionRange.start.col, this.selectionRange.end.col)
      
      // 标记整个范围为脏区域
      for (let row = minRow; row <= maxRow; row++) {
        for (let col = minCol; col <= maxCol; col++) {
          this.markCellDirty(row, col)
        }
      }
    }
    
    this.selectionRange = range
    
    // 标记新的选择范围为脏区域
    if (range) {
      const minRow = Math.min(range.start.row, range.end.row)
      const maxRow = Math.max(range.start.row, range.end.row)
      const minCol = Math.min(range.start.col, range.end.col)
      const maxCol = Math.max(range.start.col, range.end.col)
      
      for (let row = minRow; row <= maxRow; row++) {
        for (let col = minCol; col <= maxCol; col++) {
          this.markCellDirty(row, col)
        }
      }
    }
  }

  // 设置编辑单元格
  setEditingCell(cell: CellPosition | null): void {
    // 标记旧的编辑单元格为脏区域
    if (this.editingCell) {
      this.markCellDirty(this.editingCell.row, this.editingCell.col)
    }
    
    this.editingCell = cell
    
    // 标记新的编辑单元格为脏区域
    if (cell) {
      this.markCellDirty(cell.row, cell.col)
    }
  }

  // 设置悬停状态
  setHoverState(params: {
    hoveredCell?: CellPosition | null
    hoveredRow?: number
    hoveredColumn?: number
  }): void {
    // 标记旧的悬停状态为脏区域
    if (this.hoveredCell) {
      this.markCellDirty(this.hoveredCell.row, this.hoveredCell.col)
    }
    if (this.hoveredRow >= 0) {
      this.markRowDirty(this.hoveredRow)
    }
    if (this.hoveredColumn >= 0) {
      this.markColumnDirty(this.hoveredColumn)
    }
    
    // 更新悬停状态
    if (params.hoveredCell !== undefined) {
      this.hoveredCell = params.hoveredCell
      if (params.hoveredCell) {
        this.markCellDirty(params.hoveredCell.row, params.hoveredCell.col)
      }
    }
    if (params.hoveredRow !== undefined) {
      this.hoveredRow = params.hoveredRow
      if (params.hoveredRow >= 0) {
        this.markRowDirty(params.hoveredRow)
      }
    }
    if (params.hoveredColumn !== undefined) {
      this.hoveredColumn = params.hoveredColumn
      if (params.hoveredColumn >= 0) {
        this.markColumnDirty(params.hoveredColumn)
      }
    }
  }

  // 设置滚动条悬停状态
  setScrollbarHoverState(vertical: boolean | null, horizontal: boolean | null): void {
    const oldVertical = this.isHoveringVerticalScrollbar
    const oldHorizontal = this.isHoveringHorizontalScrollbar
    
    if (vertical !== null) this.isHoveringVerticalScrollbar = vertical
    if (horizontal !== null) this.isHoveringHorizontalScrollbar = horizontal
    
    // 如果滚动条悬停状态改变，标记滚动条区域为脏
    if (oldVertical !== this.isHoveringVerticalScrollbar || oldHorizontal !== this.isHoveringHorizontalScrollbar) {
      // 标记滚动条区域为脏（简化处理，标记整个滚动条区域）
      const scrollbarWidth = this.scrollManager.getScrollbarWidth()
      
      if (oldVertical !== this.isHoveringVerticalScrollbar) {
        this.markDirty({
          x: this.canvasLogicalWidth - scrollbarWidth,
          y: 0,
          width: scrollbarWidth,
          height: this.canvasLogicalHeight
        })
      }
      
      if (oldHorizontal !== this.isHoveringHorizontalScrollbar) {
        this.markDirty({
          x: 0,
          y: this.canvasLogicalHeight - scrollbarWidth,
          width: this.canvasLogicalWidth,
          height: scrollbarWidth
        })
      }
    }
  }

  // 设置当前单元格
  setCurrentCell(cell: CellPosition | null): void {
    // 标记旧的当前单元格为脏区域
    if (this.currentCell) {
      this.markCellDirty(this.currentCell.row, this.currentCell.col)
    }
    
    this.currentCell = cell
    
    // 标记新的当前单元格为脏区域
    if (cell) {
      this.markCellDirty(cell.row, cell.col)
    }
  }

  // 设置选中的行
  setSelectedRows(rows: number[]): void {
    this.selectedRows.clear()
    rows.forEach(row => this.selectedRows.add(row))
  }
  
  // 设置选中的列
  setSelectedColumns(columns: number[]): void {
    this.selectedColumns.clear()
    columns.forEach(col => this.selectedColumns.add(col))
  }
  
  // 设置选择模式
  setSelectionMode(mode: SelectionMode): void {
    this.selectionMode = mode
  }

  // 判断单元格是否被选中
  private isCellSelected(row: number, col: number): boolean {
    // 检查行选择
    if (this.selectedRows.has(row)) {
      return true
    }
    
    // 检查列选择
    if (this.selectedColumns.has(col)) {
      return true
    }
    
    // 检查单个选中
    if (this.selectedCells.has(`${row}:${col}`)) {
      return true
    }
    
    // 检查范围选中
    if (this.selectionRange) {
      const minRow = Math.min(this.selectionRange.start.row, this.selectionRange.end.row)
      const maxRow = Math.max(this.selectionRange.start.row, this.selectionRange.end.row)
      const minCol = Math.min(this.selectionRange.start.col, this.selectionRange.end.col)
      const maxCol = Math.max(this.selectionRange.start.col, this.selectionRange.end.col)
      
      return row >= minRow && row <= maxRow && col >= minCol && col <= maxCol
    }
    
    return false
  }

  // 更新主题
  updateTheme(theme: ThemeOptions): void {
    this.theme = { ...this.theme, ...theme }
  }

  // 切换行号显示
  toggleRowNumbers(show: boolean): void {
    this.showRowNumber = show
  }

  // 切换网格线显示
  toggleGridLines(show: boolean): void {
    this.showGridLines = show
  }

  // 渲染复制/剪切边框
  private renderClipboardBorder(viewport: any): void {
    // 获取EventManager的剪贴板数据
    const eventManager = (this as any).eventManager
    if (!eventManager || typeof eventManager.getClipboardData !== 'function') return
    
    const clipboardData = eventManager.getClipboardData()
    if (!clipboardData || !clipboardData.cells || clipboardData.cells.length === 0) return
    
    // 设置剪切区域
    this.ctx.save()
    const headerHeight = ('getHeaderHeight' in this.scrollManager) 
      ? (this.scrollManager as any).getHeaderHeight() 
      : (this.scrollManager as any).headerHeight || 35
    
    const scrollbarWidth = ('getScrollbarWidth' in this.scrollManager) 
      ? (this.scrollManager as any).getScrollbarWidth() 
      : (this.scrollManager as any).scrollbarWidth || 10
    const scrollbarInfo = this.scrollManager.getScrollbarInfo()
    const clipWidth = this.canvasLogicalWidth - (scrollbarInfo.vertical.visible ? scrollbarWidth : 0)
    const clipHeight = this.canvasLogicalHeight - headerHeight - (scrollbarInfo.horizontal.visible ? scrollbarWidth : 0)
    
    this.ctx.beginPath()
    this.ctx.rect(0, headerHeight, clipWidth, clipHeight)
    this.ctx.clip()
    
    // 设置虚线样式
    this.ctx.strokeStyle = clipboardData.isCut ? defaultTheme.error : defaultTheme.success // 使用主题的错误色和成功色
    this.ctx.lineWidth = 2
    this.ctx.setLineDash([5, 3])
    
    // 如果是连续区域，绘制整体边框
    const cells = clipboardData.cells as CellPosition[]
    const minRow = Math.min(...cells.map((c: CellPosition) => c.row))
    const maxRow = Math.max(...cells.map((c: CellPosition) => c.row))
    const minCol = Math.min(...cells.map((c: CellPosition) => c.col))
    const maxCol = Math.max(...cells.map((c: CellPosition) => c.col))
    
    // 检查是否是连续区域
    const isContiguous = cells.length === (maxRow - minRow + 1) * (maxCol - minCol + 1)
    
    if (isContiguous) {
      // 绘制整体边框
      const columns = this.dataManager['columns']
      
      // 使用 scrollManager 的方法来获取考虑了滚动偏移的坐标
      const x1 = this.scrollManager.getColumnX(minCol) + this.rowNumberWidth
      const x2 = this.scrollManager.getColumnX(maxCol) + (columns[maxCol]?.width || 100) + this.rowNumberWidth
      
      const y1 = this.scrollManager.getRowY(minRow)
      const y2 = this.scrollManager.getRowY(maxRow + 1)
      
      this.ctx.strokeRect(x1, y1, x2 - x1, y2 - y1)
    } else {
      // 绘制每个单元格的边框
      cells.forEach((cell: CellPosition) => {
        if (cell.row >= viewport.startRow && cell.row <= viewport.endRow && 
            cell.col >= viewport.startCol && cell.col <= viewport.endCol) {
          const columns = this.dataManager['columns']
          const column = columns[cell.col]
          const x = this.scrollManager.getColumnX(cell.col) + this.rowNumberWidth  // 始终加上行号列宽度
          const y = this.scrollManager.getRowY(cell.row)
          const width = column.width || 100
          const height = this.scrollManager.getRowHeight(cell.row)
          
          this.ctx.strokeRect(x, y, width, height)
        }
      })
    }
    
    this.ctx.setLineDash([])
    this.ctx.restore()
  }

  // 设置EventManager引用（需要在构造函数中调用）
  setEventManager(eventManager: any): void {
    (this as any).eventManager = eventManager
  }

  // 重置调试标志（用于数据更新时）
  resetDebugFlags(): void {
    this.debugLogged = false
    this.cellDebugLogged = false
  }

  // 渲染填充柄
  private renderFillHandle(): void {
    if (!this.currentCell && !this.selectionRange) return
    
    const columns = this.dataManager['columns']
    let handleX = 0
    let handleY = 0
    let cellWidth = 0
    let cellHeight = 0
    
    if (this.selectionRange) {
      // 如果有范围选择，填充柄在右下角
      const endCell = {
        row: Math.max(this.selectionRange.start.row, this.selectionRange.end.row),
        col: Math.max(this.selectionRange.start.col, this.selectionRange.end.col)
      }
      
      // 检查列索引是否有效
      if (endCell.col < 0 || endCell.col >= columns.length) return
      
      const column = columns[endCell.col]
      if (!column) return
      
      handleX = this.scrollManager.getColumnX(endCell.col) + this.rowNumberWidth  // 始终加上行号列宽度
      handleY = this.scrollManager.getRowY(endCell.row)
      cellWidth = column.width || 100
      cellHeight = this.scrollManager.getRowHeight(endCell.row)
    } else if (this.currentCell) {
      // 单个单元格选中时
      
      // 检查列索引是否有效
      if (this.currentCell.col < 0 || this.currentCell.col >= columns.length) return
      
      const column = columns[this.currentCell.col]
      if (!column) return
      
      handleX = this.scrollManager.getColumnX(this.currentCell.col) + this.rowNumberWidth  // 始终加上行号列宽度
      handleY = this.scrollManager.getRowY(this.currentCell.row)
      cellWidth = column.width || 100
      cellHeight = this.scrollManager.getRowHeight(this.currentCell.row)
    }
    
    // 设置剪切区域
    this.ctx.save()
    const headerHeight = ('getHeaderHeight' in this.scrollManager) 
      ? (this.scrollManager as any).getHeaderHeight() 
      : (this.scrollManager as any).headerHeight || 35
    
    const scrollbarWidth = ('getScrollbarWidth' in this.scrollManager) 
      ? (this.scrollManager as any).getScrollbarWidth() 
      : (this.scrollManager as any).scrollbarWidth || 10
    const scrollbarInfo = this.scrollManager.getScrollbarInfo()
    const clipWidth = this.canvasLogicalWidth - (scrollbarInfo.vertical.visible ? scrollbarWidth : 0)
    const clipHeight = this.canvasLogicalHeight - headerHeight - (scrollbarInfo.horizontal.visible ? scrollbarWidth : 0)
    
    this.ctx.beginPath()
    this.ctx.rect(0, headerHeight, clipWidth, clipHeight)
    this.ctx.clip()
    
    // 绘制填充柄（右下角的小方块）
    const handleSize = 8
    const x = handleX + cellWidth - handleSize
    const y = handleY + cellHeight - handleSize
    
    this.ctx.fillStyle = this.theme.primaryColor
    this.ctx.fillRect(x, y, handleSize, handleSize)
    
    this.ctx.restore()
  }

  // 设置分页信息
  setPageInfo(currentPage: number, pageSize: number): void {
    this.pageInfo = { currentPage, pageSize }
  }
  
  // 设置排序配置
  setSortConfig(column: string | null, direction: 'asc' | 'desc' | null): void {
    this.sortConfig = { column, direction }
    // 标记表头为脏区域以重绘排序指示器
    this.markDirty({
      x: 0,
      y: 0,
      width: this.canvasLogicalWidth,
      height: this.scrollManager.getHeaderHeight()
    })
  }

  // 初始化离屏Canvas
  private initOffscreenCanvas(): void {
    this.offscreenCanvas = document.createElement('canvas')
    this.offscreenCtx = this.offscreenCanvas.getContext('2d')!
    this.offscreenCanvas.width = this.canvasLogicalWidth
    this.offscreenCanvas.height = this.canvasLogicalHeight
  }
  
  // 性能优化：缓存的文本测量
  private measureTextCached(text: string, font?: string): number {
    const currentFont = font || this.ctx.font
    const cacheKey = `${currentFont}::${text}`
    
    // 检查缓存
    const cachedWidth = this.textMeasureCache.get(cacheKey)
    if (cachedWidth !== undefined) {
      return cachedWidth
    }
    
    // 测量文本
    const savedFont = this.ctx.font
    if (font) {
      this.ctx.font = font
    }
    const width = this.ctx.measureText(text).width
    if (font) {
      this.ctx.font = savedFont
    }
    
    // 添加到缓存
    this.textMeasureCache.set(cacheKey, width)
    
    return width
  }
  
  // 标记脏区域
  markDirty(region?: DirtyRegion): void {
    if (!region) {
      this.isFullRedrawNeeded = true
      this.dirtyRegions = []
      return
    }
    
    // 合并重叠的脏区域
    let merged = false
    for (let i = 0; i < this.dirtyRegions.length; i++) {
      const existing = this.dirtyRegions[i]
      if (this.regionsOverlap(existing, region)) {
        this.dirtyRegions[i] = this.mergeRegions(existing, region)
        merged = true
        break
      }
    }
    
    if (!merged) {
      this.dirtyRegions.push(region)
    }
    
    // 如果脏区域太多，标记为需要全量重绘
    if (this.dirtyRegions.length > 10) {
      this.isFullRedrawNeeded = true
      this.dirtyRegions = []
    }
  }
  
  // 检查区域是否重叠
  private regionsOverlap(r1: DirtyRegion, r2: DirtyRegion): boolean {
    return !(r1.x + r1.width < r2.x || 
             r2.x + r2.width < r1.x || 
             r1.y + r1.height < r2.y || 
             r2.y + r2.height < r1.y)
  }
  
  // 合并两个区域
  private mergeRegions(r1: DirtyRegion, r2: DirtyRegion): DirtyRegion {
    const x = Math.min(r1.x, r2.x)
    const y = Math.min(r1.y, r2.y)
    const x2 = Math.max(r1.x + r1.width, r2.x + r2.width)
    const y2 = Math.max(r1.y + r1.height, r2.y + r2.height)
    
    return {
      x,
      y,
      width: x2 - x,
      height: y2 - y
    }
  }
  
  // 重置脏区域
  private resetDirtyRegions(): void {
    this.dirtyRegions = []
    this.isFullRedrawNeeded = false
  }
  
  // 更新离屏Canvas尺寸
  private updateOffscreenCanvasSize(): void {
    if (this.offscreenCanvas && this.offscreenCtx) {
      this.offscreenCanvas.width = this.canvasLogicalWidth
      this.offscreenCanvas.height = this.canvasLogicalHeight
      this.needsOffscreenRedraw = true
    }
  }
  
  // 渲染脏区域
  private renderDirtyRegions(): void {
    if (this.dirtyRegions.length === 0) return
    
    // 合并相邻的脏区域
    this.optimizeDirtyRegions()
    
    const viewport = this.scrollManager.getViewport()
    
    // 批量渲染脏区域
    this.ctx.save()
    
    // 创建合并的裁剪区域
    this.ctx.beginPath()
    for (const region of this.dirtyRegions) {
      this.ctx.rect(region.x, region.y, region.width, region.height)
    }
    this.ctx.clip()
    
    // 清除裁剪区域
    for (const region of this.dirtyRegions) {
      this.ctx.clearRect(region.x, region.y, region.width, region.height)
    }
    
    // 从离屏Canvas复制背景（如果有）
    if (this.offscreenCanvas) {
      for (const region of this.dirtyRegions) {
        this.ctx.drawImage(
          this.offscreenCanvas,
          region.x, region.y, region.width, region.height,
          region.x, region.y, region.width, region.height
        )
      }
    }
    
    // 渲染动态内容
    this.renderDynamicContent(viewport)
    
    this.ctx.restore()
    
    // 重置脏区域
    this.resetDirtyRegions()
  }
  
  // 优化脏区域（合并相邻区域）
  private optimizeDirtyRegions(): void {
    if (this.dirtyRegions.length < 2) return
    
    let optimized = false
    do {
      optimized = false
      for (let i = 0; i < this.dirtyRegions.length - 1; i++) {
        for (let j = i + 1; j < this.dirtyRegions.length; j++) {
          if (this.shouldMergeRegions(this.dirtyRegions[i], this.dirtyRegions[j])) {
            this.dirtyRegions[i] = this.mergeRegions(this.dirtyRegions[i], this.dirtyRegions[j])
            this.dirtyRegions.splice(j, 1)
            optimized = true
            break
          }
        }
        if (optimized) break
      }
    } while (optimized)
    
    // 如果合并后的区域太大（超过画布的50%），直接全量重绘
    const totalArea = this.dirtyRegions.reduce((sum, r) => sum + r.width * r.height, 0)
    const canvasArea = this.canvasLogicalWidth * this.canvasLogicalHeight
    if (totalArea > canvasArea * 0.5) {
      this.isFullRedrawNeeded = true
      this.dirtyRegions = []
    }
  }
  
  // 判断是否应该合并两个区域
  private shouldMergeRegions(r1: DirtyRegion, r2: DirtyRegion): boolean {
    // 如果重叠，应该合并
    if (this.regionsOverlap(r1, r2)) return true
    
    // 如果相邻（间距小于阈值），应该合并
    const threshold = 50
    const horizontalGap = Math.max(0, Math.max(r1.x, r2.x) - Math.min(r1.x + r1.width, r2.x + r2.width))
    const verticalGap = Math.max(0, Math.max(r1.y, r2.y) - Math.min(r1.y + r1.height, r2.y + r2.height))
    
    return horizontalGap < threshold && verticalGap < threshold
  }

  // 标记单元格为脏区域
  markCellDirty(row: number, col: number): void {
    const columns = this.dataManager['columns']
    if (col < 0 || col >= columns.length) return
    
    const column = columns[col]
    const x = this.scrollManager.getColumnX(col) + this.rowNumberWidth
    const y = this.scrollManager.getRowY(row)
    const width = column.width || 100
    const height = this.scrollManager.getRowHeight(row)
    
    this.markDirty({
      x: x - 1,
      y: y - 1,
      width: width + 2,
      height: height + 2
    })
  }
  
  // 标记行为脏区域
  markRowDirty(row: number): void {
    const y = this.scrollManager.getRowY(row)
    const height = this.scrollManager.getRowHeight(row)
    
    this.markDirty({
      x: 0,
      y: y - 1,
      width: this.canvasLogicalWidth,
      height: height + 2
    })
  }
  
  // 标记列为脏区域
  markColumnDirty(col: number): void {
    const columns = this.dataManager['columns']
    if (col < 0 || col >= columns.length) return
    
    const column = columns[col]
    const x = this.scrollManager.getColumnX(col) + this.rowNumberWidth
    const width = column.width || 100
    
    this.markDirty({
      x: x - 1,
      y: 0,
      width: width + 2,
      height: this.canvasLogicalHeight
    })
  }
} 